import { CommandDialog } from '@amcax/base';
import { i18n, nmAppErrorLog } from '@app-nextmesh/common/utils';
import { documentV2 } from '@app-nextmesh/domain';
import {
  NMToolBaseCommand,
  NMToolCmdDialogParams,
} from '@app-nextmesh/types/command';
import { clearMesh, renderMesh } from '@app-nextmesh/utils/renderModel';
import { useAsyncEffect } from 'ahooks';
import {
  Form,
  FormInstance,
  InputNumber,
  Table,
  TableProps,
  Tabs,
  TabsProps,
} from 'antd';
import { createContext, useContext, useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import './style.scss';

interface IQualityItem {
  criteria: string;
  compare: string; // < > = etc.
  value: number;
}
interface IQualityForm {
  '2D': IQualityItem[];
  '3D': IQualityItem[];
}

type IDataSource = IQualityItem & {
  key: string;
};

const render = async (params) => {
  const data = await documentV2.queryMeshQuality(params);
  if (data?.mesh) {
    renderMesh([data.mesh]);
  }
};

function MyTable({
  tab,
  data,
  onItemChange,
}: {
  tab: string; // 2D or 3D
  data: IQualityItem[];
  onItemChange: (
    index: number,
    item: IQualityItem,
    isSelected?: boolean,
  ) => void;
}) {
  const [dataSource, setDataSource] = useState<IDataSource[]>([]);
  const [currentSelectedRows, setCurrentSelectedRows] = useState<
    IQualityItem[]
  >([]);

  useEffect(() => {
    setDataSource(data.map((item) => ({ ...item, key: item.criteria })));
  }, [data]);

  const EditableContext = createContext<FormInstance | null>(null);

  const EditableRow: React.FC = ({ ...props }) => {
    const [form] = Form.useForm();
    return (
      <Form
        form={form}
        component={false}>
        <EditableContext.Provider value={form}>
          <tr {...props} />
        </EditableContext.Provider>
      </Form>
    );
  };

  interface EditableCellProps {
    title: React.ReactNode;
    editable: boolean;
    dataIndex: keyof IQualityItem;
    record: IQualityItem;
    handleSave: (record: IQualityItem) => void;
  }

  const EditableCell: React.FC<React.PropsWithChildren<EditableCellProps>> = ({
    title,
    editable,
    children,
    dataIndex,
    record,
    handleSave,
    ...restProps
  }) => {
    const [editing, setEditing] = useState(false);
    const inputRef = useRef<HTMLInputElement>(null);
    const form = useContext(EditableContext)!;

    useEffect(() => {
      if (editing) {
        inputRef.current?.focus();
      }
    }, [editing]);

    const toggleEdit = () => {
      setEditing(!editing);
      form.setFieldsValue({ [dataIndex]: record[dataIndex] });
    };

    const save = async () => {
      try {
        const values = await form.validateFields();

        toggleEdit();
        handleSave({ ...record, ...values });
      } catch (errInfo) {
        nmAppErrorLog('Save failed:', errInfo);
      }
    };

    let childNode = children;

    if (editable) {
      childNode = editing ? (
        <Form.Item
          style={{ margin: 0 }}
          name={dataIndex}
          rules={[
            {
              required: true,
              message: `${title} is required.`,
            },
          ]}>
          <InputNumber
            ref={inputRef}
            onPressEnter={save}
            onBlur={save}
            size='small'
          />
        </Form.Item>
      ) : (
        <div
          className='editable-cell-value-wrap'
          style={{ paddingInlineEnd: 24 }}
          onClick={toggleEdit}>
          {children}
        </div>
      );
    }

    return <td {...restProps}>{childNode}</td>;
  };

  type ColumnTypes = Exclude<TableProps<IQualityItem>['columns'], undefined>;
  const tableColumns: ColumnTypes[number] &
    {
      key: string;
      title: React.ReactNode;
      editable?: boolean;
      dataIndex: string;
      width?: number;
    }[] = [
    {
      title: i18n.t('criteria'),
      dataIndex: 'criteria',
      key: 'criteria',
    },
    {
      title: i18n.t('compare'),
      dataIndex: 'compare',
      key: 'compare',
    },
    {
      title: i18n.t('value'),
      dataIndex: 'value',
      key: 'value',
      editable: true,
      width: 125,
    },
  ];

  const handleSave = (row: IQualityItem) => {
    const index = dataSource.findIndex(
      (item) => row.criteria === item.criteria,
    );
    const item = dataSource[index];
    // row和item的value相同，则不进行更新
    if (row.value === item.value) {
      return;
    }
    const newData = [...dataSource];
    newData[index] = {
      ...item,
      ...row,
    };
    setDataSource(newData);
    onItemChange(
      index,
      row,
      currentSelectedRows.some((item) => item.criteria === row.criteria),
    );
  };

  const components = {
    body: {
      row: EditableRow,
      cell: EditableCell,
    },
  };
  const columns = tableColumns.map((col) => {
    if (!col.editable) {
      return col;
    }
    return {
      ...col,
      onCell: (record: IQualityItem) => ({
        record,
        editable: col.editable,
        dataIndex: col.dataIndex,
        title: col.title,
        handleSave,
      }),
    };
  });
  const rowSelection: TableProps<IQualityItem>['rowSelection'] = {
    type: 'radio',
    onChange: async (_: React.Key[], selectedRows: IQualityItem[]) => {
      try {
        await render({ [tab]: selectedRows });
      } catch (error) {
        nmAppErrorLog('render failed', error);
      }
      setCurrentSelectedRows(selectedRows);
    },
  };

  return (
    <Table
      style={{ width: '400px', height: '450px', overflow: 'auto' }}
      columns={columns as ColumnTypes}
      dataSource={dataSource}
      pagination={false}
      rowSelection={rowSelection}
      components={components}
      rowClassName={() => 'editable-row'}
      size='middle'
    />
  );
}
const WrapperStyle = styled.div`
  row-gap: 8px;
  padding: 20px;
  padding-bottom: 8px;
  display: flex;
  flex-direction: column;

  .form-dialog_footer {
    width: 100%;
    padding: 8px 0 12px !important;
  }
`;
function CmdMeshQualityDialog({ title, onClose }: NMToolCmdDialogParams) {
  const [currentTab, setCurrentTab] = useState('2D');
  const [qualityData, setQualityData] = useState<IQualityForm>({
    '2D': [],
    '3D': [],
  });

  useEffect(() => {
    return () => {
      clearMesh();
    };
  }, []);
  useAsyncEffect(async () => {
    const formData = await documentV2.listMeshQuality();
    setQualityData(formData);
  }, []);

  const onTabsChange = (key: string) => {
    setCurrentTab(key);
    // 根据currentSelectedRows判断是否选中，切换显示网格质量数据
  };

  const tabsItems: TabsProps['items'] = Object.keys(qualityData).map((key) => {
    const qualityItems: IQualityItem[] = qualityData[key];
    return {
      key,
      label: i18n.t(key),
      children: (
        <MyTable
          tab={key}
          data={qualityItems}
          onItemChange={async (index, data, isSelected) => {
            const newQualityData = { ...qualityData };
            const newData = { ...data };
            delete newData['key']; // 不保存key
            newQualityData[key][index] = data;

            try {
              await documentV2.updateMeshQuality(newQualityData);
              setQualityData(newQualityData);
              if (isSelected) {
                await render({ [key]: [data] });
              }
            } catch (error) {
              nmAppErrorLog(error);
            }
          }}
        />
      ),
    };
  });

  return (
    <CommandDialog
      title={title}
      placement='topLeft'
      onClose={onClose}>
      <WrapperStyle>
        <Tabs
          defaultActiveKey={currentTab}
          items={tabsItems}
          onChange={onTabsChange}
        />
      </WrapperStyle>
    </CommandDialog>
  );
}

export const cmdMeshQuality: NMToolBaseCommand = {
  id: 'CmdMeshQuality',
  label: 'command.mesh.quality',
  icon: 'commands/curved/analysis',
  create: (label, onClose) => (
    <CmdMeshQualityDialog
      title={i18n.t(label)}
      onClose={onClose}
    />
  ),
};
